package com.jgz.rxnet;

import android.util.Log;

import java.io.IOException;
import java.util.HashSet;
import java.util.concurrent.TimeUnit;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Observable;
import rx.Observer;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 * RxJava+Retrofit+OkHttp+Cookie缓存
 * Created by Je on 2017/6/14.
 */

public class RxNet {

    private static String mBaseUrl;
    private static HashSet<String> mCookies = new HashSet<>();
    private static HttpLoggingInterceptor.Level mLevel;


    /**
     * 初始化网络框架
     * @param baseUrl   网络请求公共部分
     * @param logLevel  网络请求的日志级别
     */
    public static void init(String baseUrl, HttpLoggingInterceptor.Level logLevel){
        mBaseUrl = baseUrl;
        mLevel = logLevel;
    }

    /**
     * 在退出App的时候，需要释放资源
     */
    public static void release(){
        mBaseUrl = null;
        mCookies.clear();
        mCookies = null;
        mLevel = null;
    }

    /**
     *  获取一个网络请求公用的接口
     * @param clazz
     * @param <T>
     * @return 公用接口对应的class
     */
    public static <T> T getService(Class<T> clazz) {
        return createService(clazz);
    }


    private static <T> T createService(Class<T> clazz) {
        return new Retrofit.Builder()
                .baseUrl(mBaseUrl)
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .build()
                .create(clazz);
    }


    private static <T> Observable.Transformer<T, T> applyScheduer() {
        return observable -> observable.map(t -> t)
                .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
    }


    public static <T> Subscription newObserver(Observable<T> observable, Observer<T> observer) {
        return observable.compose(applyScheduer()).subscribe(observer);
    }



    /**
     * 将服务器Cookies保存起来
     */
    static class ReceivedCookiesInterceptor implements Interceptor {

        @Override
        public Response intercept(Chain chain) throws IOException {

            Response originalResponse = chain.proceed(chain.request());

            if (!originalResponse.headers("Set-Cookie").isEmpty()) {
                HashSet<String> cookies = new HashSet<>();

                for (String header : originalResponse.headers("Set-Cookie")) {
                    cookies.add(header);
                }

                mCookies = cookies;
            }

            return originalResponse;
        }
    }

    /**
     * 将Cookies传递给服务器
     */
    static class AddCookiesInterceptor implements Interceptor {

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request.Builder builder = chain.request().newBuilder();

            HashSet<String> preferences = mCookies;

            for (String cookie : preferences) {
                builder.addHeader("Cookie", cookie);
                Log.v("OkHttp", "Adding Header: " + cookie);
            }

            return chain.proceed(builder.build());
        }
    }

    private static HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(message ->
            Log.i("网络请求", message)).setLevel(mLevel);

    private static OkHttpClient client = new OkHttpClient.Builder()
            //添加interceptor,日志拦截器
            .addInterceptor(interceptor)
            .addInterceptor(new ReceivedCookiesInterceptor())
            .addInterceptor(new AddCookiesInterceptor())
            //设置连接超时的时间
            .connectTimeout(10L, TimeUnit.SECONDS)
            //设置读取超时的时间
            .readTimeout(10L, TimeUnit.SECONDS)
            //设置失败重连
            .retryOnConnectionFailure(true)
            .build();

}
